﻿using System;
using System.Collections.Generic;
using System.Text;
using Magnet.Engine.Physics;
using Magnet.Engine.Entities;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace Magnet.Engine
{
    public class World
    {
        //The "normal" time change is what is considered a time change that will apply a delta of 1.
        //A delta that is higher than this will apply a slower update, and lower than this is faster.
        public const float NORMAL_TIME_CHANGE = 0.015f;

        private static List<Entity> entities;
        private static List<Arbiter> collisions;
        private static Level level;

        /// <summary>
        /// Initializes the World starting at the passed level.
        /// </summary>
        /// <param name="level">The Level to use.</param>
        public static void Initialize(String levelName, Player player)
        {
            entities = new List<Entity>();
            collisions = new List<Arbiter>();
            LoadLevel(levelName,player);
        }

        public static void Draw(SpriteBatch batch)
        {
            level.Draw(batch);

            ArrowManager.Draw(batch);

            entities.ForEach(delegate(Entity e)
            {
                e.Draw(batch);
            });
        }

        public static void Update(float delta)
        {
            //Clear out the old collisions.
            collisions.Clear();

            //Create a list to manage deletions.
            List<int> deletionList = new List<int>();

            //Loop through all the Entity's and factor collisions.
            for (int i = 0; i < entities.Count; i++)
            {
                Entity e = entities[i];

                //If the Entity is marked for removal, add it to the deletion list.
                if (e.IsMarkedForRemoval)
                {
                    deletionList.Add(i);
                }
                //Otherwise it can act and be added to collisions.
                else
                {
                    for (int j = i+1; j < entities.Count; j++)
                    {
                        Entity e2 = entities[j];

                        if (e.Intersects(e2))
                        {
                            collisions.Add(new Arbiter(e, e2));
                        }
                    }

                    //After collisions concerning this Entity have been found, it can update.
                    e.Update(delta);
                }
            }

            //Now remove everything that was in the deletion list.
            for (int i = deletionList.Count-1; i >= 0; i--)
            {
                entities.RemoveAt(deletionList[i]);
            }
        }

        public static int GetCollisionCount()
        {
            return collisions.Count;
        }

        public static Arbiter GetCollisionAt(int i)
        {
            return collisions[i];
        }

        public static int GetEntityCount()
        {
            return entities.Count;
        }

        public static Entity GetEntityAt(int i)
        {
            return entities[i];
        }

        public static void AddEntity(Entity e)
        {
            entities.Add(e);
        }

        public static void LoadLevel(String levelName, Player player)
        {
            //Clear out our Entity list.
            entities.Clear();

            //Load the level.
            level = new Level(levelName,player);

            AddEntity(player);
        }

        /// <summary>
        /// Returns all arbiters that are relevant to the passed Entity in a new List.
        /// A collision is relevant to an Entity if that Entity exists in the Arbiter.
        /// </summary>
        /// <param name="e">The Entity we want relevant collisons for.</param>
        /// <returns>A new list of all relevant arbiters.</returns>
        public static List<Arbiter> GetRelevantCollisions(Entity e)
        {
            //NOTE - This could be highly optimized by having a sorted list of collisions.
            //At this point, however, it doesn't seem worth the time.

            List<Arbiter> relevant = new List<Arbiter>();
            collisions.ForEach(delegate(Arbiter a)
            {
                if (a.ConcernsEntity(e))
                    relevant.Add(a);
            });

            return relevant;
        }
    }
}
